"""
    案例背景：
        演示KNN算法 识别图片 ， 即：手写案例识别

    介绍：
        每张图片都是有28*28像素组成，即：我们csv文件中每一行都有784像素点。表示图片(每个像素)的颜色
        最终构成图像
"""
import matplotlib.pyplot as plt
import pandas as pd
from sklearn.metrics import accuracy_score
from sklearn.model_selection import train_test_split
from sklearn.neighbors import KNeighborsClassifier
import joblib     #持久化保存本地
from collections import Counter #查看所有标签的分布情况
import numpy as np

#1：定义函数  接受用户传入的索引 ，展示该所有对应的图片
# （excel的行号从1开始，索引从0开始 ，找到正确的数值 ，应该行号-1）
def show_digit(idx):
    #1、读取数据，获取数据集源
    df=pd.read_csv("../data/手写数字识别.csv")
    # print(df)  #[42000 行 x 785 列]

    #2、判断传入的索引是否越界
    if idx<0 or idx>len(df)-1:
        print("索引越界！")
        return

    #3、走到这里，说明索引没有越界，正常获取数据
    # iloc 根据索引来获取
    # 格式： df.iloc[行号,列索引]
    x=df.iloc[:,1:]
    y=df.iloc[:,0]
    # print(f"像素的形状是:{x.shape}")  #(42000, 784)

    # print(f"您传入的索引对应的数字是:{y[idx]}")

    #4、绘制图片  把(784,)  转换成(28*28)
    x=x.iloc[idx].values.reshape(28,28)
    # print(x)

    #5、绘制具体的灰度图
    plt.imshow(x,cmap='gray')
    plt.axis('off')  #不显示坐标轴
    plt.show()


    #查看所有的标签的分布情况
    print(f"查看所有标签的分布情况:{Counter(y)}")

#2、定义函数 ，训练模型 ，并保存好训练的模型
def train_model():
    #1、加载数据集
    df=pd.read_csv("../data/手写数字识别.csv")

    #2、数据预处理
    #2-1拆分特征列
    x=df.iloc[:,1:]  #特征列
    #2-2拆分标签列
    y=df.iloc[:,0]    #标签列

    #3、特征工程
    # 特征预处理 x是像素[0,255 ] y数值：[0,9]
    x=x/255

    #4、拆分训练集和测试集
    #参1：特征列
    #参2：标签列
    #参3：测试集比例
    #参4：随机种子
    #参5：参考y值进行抽取，保持标签比例（数据均衡）
    x_train,x_test,y_train,y_test=train_test_split(x,y,test_size=0.2,random_state=18,stratify=y)

    #5、模型训练
    es=KNeighborsClassifier(n_neighbors=3)
    es.fit(x_train,y_train)

    #6、模型评估
    print(f"准确率：{accuracy_score(y_test,es.predict(x_test))}")

    #7、保存模型
    joblib.dump(es,"../model/手写数字识别.pkl")  #pickle文件：python独有文件类型
    print("模型保存成功！")

#3、定义函数 ，加载模型
def use_model(r):
    #1、读取数据，绘制图片
    img=plt.imread(f"{r}")
    # print(img)  #28*28

    #2、读取模型
    knn=joblib.load("../model/手写数字识别.pkl")

    #3、模型预测
    # 将图像数据转换为与训练时相同的格式（DataFrame并包含特征名）
    img_reshaped = img.reshape(1, 784)

    # 如果模型有特征名信息，则创建具有相同特征名的DataFrame
    if hasattr(knn, 'feature_names_in_'):
        img_df = pd.DataFrame(img_reshaped, columns=knn.feature_names_in_)
        y_predict = knn.predict(img_df)
    else:
        y_predict = knn.predict(img_reshaped)

    print(f"预测结果为:{y_predict}")

if __name__ == '__main__':
    #绘制数字
    # show_digit(10)
    #模型训练 保存模型
    # train_model()
    #模型预测（调用模型）
    use_model("../data/img/digit_3.png")
